/*
 * File:    BufferInterface.java
 * Created: 30-Oct-2007
 *
 * by Kenji Hollis <kenji@bitgatesoftware.com>
 * Released under the Creative Commons License version 2.5
 */

package com.bitgate.util.buffer;

/**
 * This is an interface that provides the use of a buffering system for buffering data for either incoming or outgoing
 * transactions.  It also provides a mechanism for the buffer to be transformed into a different type of buffer, which can
 * be used to save on memory usage, depending on the type of buffer that was instantiated using the {@link BufferFactory}.
 * <p></p>
 * As chunks of data are pulled from the buffer, the buffer must free up that amount of memory from the buffer storage
 * that is in use.  Each subsequent {@link #get()} request will pull data from the buffer, and free up space for it to be used
 * at a later time, or for additional storage later.
 * 
 * @author Kenji Hollis &lt;kenji@bitgatesoftware.com&gt;
 * @since 0.1
 */
public interface BufferInterface {
	
	/**
	 * Appends a block of data to the end of a buffer.
	 * 
	 * @param data The <code>byte[]</code> containing the data to append.
	 * @throws BufferException on any errors.
	 */
	void appendData(byte[] data) throws BufferException;
	
	/**
	 * Inserts a block of data to the head of a buffer.
	 * 
	 * @param data The <code>byte[]</code> containing the data to insert.
	 * @throws BufferException on any errors.
	 */
	void insertData(byte[] data) throws BufferException;
	
	/**
	 * Indicates the size of the buffer.
	 * 
	 * @return <code>long</code> containing the size of the buffer.
	 */
	long size();
	
	/**
	 * Returns the contents of the entire buffer.
	 * 
	 * @return <code>byte[]</code> containing the buffer contents, <code>null</code> if no data remains.
	 */
	byte[] get();
	
	/**
	 * Returns a chunk of data from the buffer in the size specified.
	 * 
	 * @param size <code>long</code> indicating the number of bytes to retrieve from the buffer.
	 * @return <code>byte[]</code> containing the data retrieved, <code>null</code> if no data remains.
	 */
	byte[] get(long size);
	
	/**
	 * This returns a copy of the entire contents of this buffer, and clears the buffer.
	 * 
	 * @return <code>byte[]</code> containing the buffer contents, <code>null</code> if no data remains.
	 */
	byte[] take();
	
	/**
	 * Removes a chunk of data from the head of the buffer, and returns it in the size specified.
	 * 
	 * @param size <code>long</code> indicating the number of bytes to retrieve from the buffer.
	 * @return <code>byte[]</code> containing the data retrieved, <code>null</code> if no data remains.
	 */
	byte[] take(long size);
	
	/**
	 * Sets the size limit of this buffer.  0 indicates unlimited, which is the default.
	 * 
	 * @param size <code>long</code> containing the number of bytes to limit this buffer to.
	 * @throws BufferException if the limit is smaller than the size of the current buffer.
	 */
	void setLimit(long size) throws BufferException;
	
	/**
	 * Returns the number of bytes this buffer is limited to.  0 indicates unlimited.
	 * 
	 * @return <code>long</code> containing the buffer limit size, 0 indicates unlimited.
	 */
	long getLimit();

	/**
	 * Clears the contents of this buffer.
	 * 
	 * @throws BufferException on any errors.
	 */
	void clear() throws BufferException;
	
	/**
	 * Deallocates the currently used buffer.  This is called as a failsafe, and as a way to clear out memory from
	 * Java memory.
	 * 
	 * @throws BufferException on any errors.
	 */
	void deallocate() throws BufferException;
	
	/**
	 * If this {@link BufferInterface} object can be persisted to disk or another storage mechanism, this buffer object will
	 * transfer the contents of its buffer to another buffer object type, and return that object.  If the buffer object could
	 * not be transferred, a {@link BufferException} is thrown.  An example use of this object would be a memory buffer that
	 * dumps to a disk buffer.
	 * <p></p>
	 * If this function is implemented, it is advised to call the {@link #deallocate()} function before returning the
	 * {@link BufferInterface} object.
	 * 
	 * @return <code>BufferInterface</code> if the buffer was transferred to persistant storage.
	 * @throws BufferException on any errors.
	 */
	BufferInterface persistToStorage() throws BufferException;
	
	/**
	 * If this {@link BufferInterface} object can persist from the storage mechanism in which it is stored to another
	 * {@link BufferInterface} object, that conversion is done here, and that object is returned.  An example of this use 
	 * would be a disk buffer that reads the contents from disk and returns a memory buffer.
	 * <p></p>
	 * If this function is implemented, it is advised to call the {@link #deallocate()} function before returning the
	 * {@link BufferInterface} object.
	 * 
	 * @return <code>BufferInterface</code> if the buffer was persisted from storage.
	 * @throws BufferException on any errors.
	 */
	BufferInterface retrieveFromStorage() throws BufferException;
	
}